package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

func main() {

	logPath := "./log/"
	os.MkdirAll(logPath, 0644)

	// 获取命令行参数列表
	args := os.Args[1:] // 从索引为1开始读取所有参数

	if len(args) != 2 {
		Pause()
		return
	}

	// go Api()

	port := args[0] // TCP 端口参数
	url := args[1]  // POST 接收地址
	listen, err := net.Listen("tcp", ":"+port)
	log.Println("Listen: ", listen.Addr().String())
	log.Println("Post Url:", url)
	if err != nil {
		log.Println("listen failed, err:", err)
	}
	for {
		conn, err := listen.Accept()
		log.Println("Accept:", conn.RemoteAddr())
		if err != nil {
			log.Println("accept failed, err:", err)
		}
		go Process(conn, url, logPath)
	}
}

func Pause() {
	fmt.Println("需要 TCP 端口和 POST Url 两个参数")
	fmt.Println()
	fmt.Println("For example:")
	fmt.Println("  hl7.service.exe 5001 http://127.0.0.1:8080/api/upload")
	fmt.Println()
	fmt.Printf("按 [回车] 键退出 ...")
	enterKey := make([]byte, 1)
	os.Stdin.Read(enterKey)
}

func Process(conn net.Conn, url, logPath string) {
	defer conn.Close()
	fileName := fmt.Sprintf("%s%d.txt", logPath, time.Now().UnixMicro())
	for {
		var buf [10240]byte
		n, err := conn.Read(buf[:])
		if err != nil {
			log.Println("read form client failed, err:", err)
			break
		}
		if buf[0] == 0x0b {
			fileName = fmt.Sprintf("%s%d.txt", logPath, time.Now().UnixMicro())
		}

		WriteLog(fileName, buf[:n])

		if bytes.Contains(buf[:n], []byte{0x1c}) {
			log.Println("finished:", fileName)
			go Post(fileName, url)
		}
	}
}

func Format(data []byte) []byte {
	str := string(data)
	str = strings.ReplaceAll(str, "\n", "")
	for _, o := range []string{"MSH", "PID", "PV1", "OBR", "OBX"} {
		str = strings.ReplaceAll(str, o, "\n"+o)
	}
	return []byte(str)
}

func Post(fileName string, url string) {
	// 创建一个新的表单对象
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// 添加要上传的文件到表单中
	filePart, err := writer.CreateFormFile("file", filepath.Base(fileName))
	if err != nil {
		log.Println("Post Error:", err.Error())
	}

	// 读取文件内容并将其写入表单中
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Println("Post Error:", err.Error())
		return
	}
	_, err = filePart.Write(Format(data))
	if err != nil {
		log.Println("Post Error:", err.Error())
		return
	}

	// 关闭表单
	err = writer.Close()
	if err != nil {
		log.Println("Post Error:", err.Error())
		return
	}

	// 设置POST请求头部信息
	request, err := http.NewRequest("POST", url, body)
	if err != nil {
		log.Println("Post Error:", err.Error())
		return
	}
	request.Header.Set("Content-Type", writer.FormDataContentType())

	// 发送POST请求
	client := &http.Client{}
	resp, err := client.Do(request)
	if err != nil {
		log.Println("Post Error:", err.Error())
		return
	}
	defer resp.Body.Close()

	log.Println("Post Status Code: ", resp.StatusCode)
}

func WriteLog(fileName string, data []byte) {
	file, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		log.Println("无法打开文件", fileName, ": ", err)
	}
	defer file.Close()
	_, err = fmt.Fprintln(file, string(data))
	if err != nil {
		log.Println("无法写入文件:", err)
	}
}

/*
test api for receive hl7 file
*/
func Api() {
	gin.SetMode(gin.ReleaseMode)

	router := gin.Default()

	// 定义POST路由处理函数
	router.POST("/api/hl7", func(c *gin.Context) {
		file, err := c.FormFile("file") // 获取上传的文件对象
		if err != nil {
			log.Println(err.Error())
			c.JSON(500, gin.H{"error": "无法读取文件"})
			return
		}

		err = c.SaveUploadedFile(file, file.Filename) // 保存文件到指定位置
		if err != nil {
			log.Println(err.Error())
			c.JSON(500, gin.H{"error": "无法保存文件"})
			return
		}

		c.JSON(200, gin.H{
			"message":   "文件已成功上传",
			"filename":  file.Filename,
			"size":      file.Size / 1024, // 转换为KB单位
			"mime_type": file.Header["Content-Type"][0],
		})

		data, _ := os.ReadFile(file.Filename)

		for _, str := range strings.Split(string(data), "\n") {
			if len(str) > 100 {
				log.Println(str[:100] + "...")
			} else if len(str) > 3 {
				log.Println(str)
			}
		}

	})

	router.Run(":8080")
}
